//-------------------------------------------------------------------
//	Copyright (c) 2013  Zhirnov Andrey
//	This file is part of the "Noise Library" project.
//	See copyright notice in "linNoiseCL.h".
//-------------------------------------------------------------------

#pragma once

#include "../CSource.h"

namespace Noise
{

	//
	// Function Source for coordinate translation.
	//

	class CSourceTranslatePoint : public CSource
	{
	// types
	protected:
		typedef CSourceTranslatePoint		Self;


	// variables
	protected:
		CSourcePtr	_src0;
		real3		_translate;


	// methods
	public:
		CSourceTranslatePoint () : _translate(0.0)
		{}

		~CSourceTranslatePoint ()
		{}

		ESourceState GetState () const
		{
			return _src0.IsNotNull() ? SOURCE_COMPLETE : UNCOMPLETE_ATTACHMENT_SOURCE;
		}
		
		virtual void Delete ()
		{
			_src0 = null;
		}

		virtual EResult GetInteger (ESourceQuery type, int *v, int count) const
		{
			CHECK_ARGUMENT_R( count >= 1, INVALID_VALUE );

			switch ( type )
			{
				case SOURCE_STATE :
					v[0] = GetState();
					return OK;

				case SOURCE_TYPE :
					v[0] = TRANSLATE_POINT;
					return OK;

				case SOURCES_COUNT :
				{
					int	count = 0;
					_src0->GetInteger( SOURCES_COUNT, &count, 1 );
					v[0] = count + 1;
					return OK;
				}

				case INPUT_SOURCES :
					v[0] = 1;
					return OK;
			}
			return INVALID_ENUM;
		}

		virtual EResult SetArg (EArgument type, CSourcePtr src)
		{
			switch ( type )
			{
				case SOURCE_0 :	_src0 = src;	return OK;
			}
			return INVALID_ENUM;
		}

		virtual EResult SetArg (EArgument type, const real *v, int count)
		{
			CHECK_ARGUMENT_R( count >= 3, INVALID_VALUE );

			switch ( type )
			{
				case ARG_TRANSLATE :	_translate = real3(v);	return OK;
			}
			return INVALID_ENUM;
		}

		virtual EResult GetArg (EArgument type, CSourcePtr &src) const
		{
			switch ( type )
			{
				case SOURCE_0 :	src = _src0;	return OK;
			}
			return INVALID_ENUM;
		}

		virtual EResult GetArg (EArgument type, real *v, int count) const
		{
			CHECK_ARGUMENT_R( count >= 3, INVALID_VALUE );

			switch ( type )
			{
				case ARG_TRANSLATE :	MemCopy( v, _translate.ptr(), sizeof(_translate) );	return OK;
			}
			return INVALID_ENUM;
		}
		
		virtual CSourcePtr Clone () const override
		{
			return new Self();
		}
		
		virtual void PreBuild (const TPreBuildData &data) override
		{
			data.Push( _src0.ptr() );
		}

		virtual bool BuildFunction (TFunctionData &data) override
		{
			CSource::BuildFunctionHeader( data.source, _id );
			data.source
				<< "( " << CSource::FunctionName() << _src0->GetSourceId() <<
				"( vPoint + (real3)( "
				<< _translate.x << ", " << _translate.y << ", " << _translate.z
				<< " ) ) )\n";
			
			return true;
		}
		
		NATIVE(
		template < typename Real, Real (CSource::*NativeFunction)(const TVec<Real,3> &) >
		Real NativeFunction (const TVec<Real,3> &vPoint)
		{
			typedef TVec<Real,3>	Real3;
			return (_src0.ptr()->*NativeFunction)( vPoint + _translate.To<Real3>() );
		}
		
		virtual float32 NativeFunction32 (const fvec3 &vPoint) override
		{
			return NativeFunction< float32, &CSource::NativeFunction32 >( vPoint );
		}

		virtual float64 NativeFunction64 (const dvec3 &vPoint) override
		{
			return NativeFunction< float64, &CSource::NativeFunction64 >( vPoint );
		})

		static bool CreateSource (CSourcePtr &src, CContext *context, ESource type)
		{
			ASSERT( type == TRANSLATE_POINT );

			src = new Self();
			return true;
		}
	};

}	// Noise